package com.zjdiepu.www.commpent;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

import javax.annotation.PreDestroy;
import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

import com.aliyun.oas.core.AliyunOASClient;
import com.aliyun.oas.ease.ArchiveManager;
import com.aliyun.oas.ease.listener.ProgressListener;
import com.aliyun.oas.ease.monitor.JobMonitor;
import com.aliyun.oas.ease.transfer.Transfer;
import com.aliyun.oas.model.common.Range;
import com.aliyun.oas.model.exception.OASClientException;
import com.aliyun.oas.model.exception.OASServerException;
import com.aliyun.oas.model.result.UploadResult;
import com.zjdiepu.www.config.OASProperty;

/**
 * 项目名称：dp-base <br/>
 * 类名称：OOSUtil <br/>
 * 类描述：阿里云归档归档对象操作 <br/>
 * 创建人：xiongxiaotun <br/>
 * 创建时间：2017年3月27日 下午3:38:34 <br/>
 * 修改人：xiongxiaotun <br/>
 * 修改时间：2017年3月27日 下午3:38:34 <br/>
 * 修改备注： <br/>
 * 
 * @version V1.0 <br/>
 */
@Component
public class OASCommpent implements InitializingBean {
	private final Logger logger = LoggerFactory.getLogger(getClass());
	/*
	 * oss配置
	 */
	@Resource
	private OASProperty oasProperty;
	/*
	 * oas客户端
	 */
	private ArchiveManager archiveManager;

	/*
	 * aliyunOAS客户端
	 */
	private AliyunOASClient aliyunOASClient;

	// ================================上传====================================

	/**
	 * 上传文件到指定的vault中 <br/>
	 * ArchiveManager的upload接口会根据文件大小判断是直接上传还是用Multipart上传，无须用户选择<br/>
	 * 
	 * @param file
	 *            需要上传的文件对象
	 * @return 返回UploadResult对象
	 * @throws OASClientException
	 *             客户端异常
	 * @throws OASServerException
	 *             服务端异常
	 */
	public String upload(File file) throws OASClientException,
			OASServerException {
		// 由此避免了用户对一长串vaultId的记忆负担
		UploadResult result = archiveManager.upload(oasProperty.getVaultName(),
				file);
		String archiveId = result.getArchiveId();
		logger.debug("File {} uploaded complete. ArchiveId={},treeEtag={}",
				file.getAbsolutePath(), archiveId, result.getTreeEtag());
		return archiveId;
	}

	/**
	 * 手工初始化Multipart上传任务
	 * 
	 * @param file
	 *            需要上传的文件
	 * @return 初始化成功的Multipart上传任务的UploadId字符串
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public String initiateMultipartUpload(File file) throws OASClientException,
			OASServerException {
		// 获得uploadId
		// 文件大小必须大于100MB，否则会抛异常提示用普通上传接口进行上传
		String uploadId = archiveManager.initiateMultipartUpload(
				oasProperty.getVaultName(), file);
		return uploadId;
	}

	/**
	 * 根据具体的UploadId上传文件。 要配合 {@link initiateMultipartUpload} 使用
	 * 
	 * @param file
	 *            需要上传的文件
	 * @param uploadId
	 *            初始化完成的Multipart的UploadId
	 * @return 上传结果对象
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public String uploadWithUploadId(File file, String uploadId)
			throws OASClientException, OASServerException {
		logger.debug("Get uploadId=" + uploadId);
		UploadResult uploadResult = archiveManager.uploadWithUploadId(
				oasProperty.getVaultName(), file, uploadId);
		String archiveId = uploadResult.getArchiveId();
		logger.debug("Archive ID=" + archiveId);
		return archiveId;
	}

	/**
	 * 上传文件到指定的vault中 <br/>
	 * ArchiveManager的upload接口会根据文件大小判断是直接上传还是用Multipart上传，无须用户选择<br/>
	 * 
	 * @param file
	 *            需要上传的文件对象
	 * @return 返回UploadResult对象
	 * @throws OASClientException
	 *             客户端异常
	 * @throws OASServerException
	 *             服务端异常
	 */
	public String uploadAsync(File file) throws OASClientException,
			OASServerException {
		final Transfer<UploadResult> bt = archiveManager.uploadAsync(
				oasProperty.getVaultName(), file);

		// 设置最大并发数，默认为3，最大为10
		bt.setNumConcurrence(5);
		bt.addProgressListener(new ProgressListener() {

			@Override
			public void onStart(String id) {
				// 任务开始时调用，其中id为Multipart Upload任务ID，对于一般上传任务id为空
				logger.debug("Start! Upload ID: " + id);
			}

			@Override
			public boolean onError(Range range, Throwable t) {
				// 出错时调用，range是出错的字节范围，t是相应的错误
				// 当返回true时，BaseTransfer会进行重试，false则放弃
				logger.debug("ERROR!!!");
				return false;
			}

			@Override
			public void onCompleted() {
				// 任务完成时调用
				logger.debug("Upload complete");
			}

			@Override
			public void onProgressed(long current, long total) {
				// 上传进度，total为文件字节大小，current为当前已上传字节数
				logger.debug("Progress: " + current + " / " + total);
			}
		});

		bt.start();

		final Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				logger.debug("Running time: " + bt.getRunningTime()
						+ " seconds");
				logger.debug("Completed size: " + bt.getCompletedSize()
						+ " bytes");
				logger.debug("Total size: " + bt.getTotalSize() + " bytes");
				logger.debug("Average speed: "
						+ bt.getAverageSpeedInBytesPerSecond() + " B/s");
				if (bt.isComplete()) {
					timer.cancel();
					synchronized (bt) {
						bt.notify();
					}
				}
			}
		}, 0, 1000);
		synchronized (bt) {
			try {
				bt.wait();
			} catch (InterruptedException e) {
				logger.error("", e);
			}
		}
		// 任务结束
		logger.debug("=============================");
		logger.debug("Running time: " + bt.getRunningTime() + " seconds");
		logger.debug("Completed size: " + bt.getCompletedSize() + " bytes");
		logger.debug("Total size: " + bt.getTotalSize() + " bytes");
		logger.debug("Average speed: " + bt.getAverageSpeedInBytesPerSecond()
				+ " B/s");
		UploadResult uploadResult = bt.getResult();
		logger.debug("Archive ID: " + uploadResult.getArchiveId());
		return uploadResult.getArchiveId();
	}

	// ================================下载====================================
	/**
	 * 提交请求下载archive任务请求
	 * 
	 * @param archiveId
	 *            需下载的archiveId
	 * @return 返回Job信息跟踪器，可用来获取Job信息，如jobId，eTag校验信息
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public JobMonitor downloadAsync(String archiveId)
			throws OASClientException, OASServerException {
		JobMonitor jobMonitor = archiveManager.downloadAsync(
				oasProperty.getVaultName(), archiveId);
		logger.debug("Job has been comitted successfully.");
		logger.debug("Your JobId=" + jobMonitor.getJobId());
		return jobMonitor;
	}

	/**
	 * 根据vault名称获得vault的目录信息
	 * 
	 * @return
	 */
	public JobMonitor downloadInventoryAsync() throws OASClientException,
			OASServerException {
		JobMonitor jobMonitor = archiveManager
				.downloadInventoryAsync(oasProperty.getVaultName());
		logger.debug("Job has been comitted successfully.");
		logger.debug("Your JobId=" + jobMonitor.getJobId());
		return jobMonitor;
	}

	/**
	 * 下载Job输出到文件，只有当Job的状态是Succeeded或Failed（到达终结状态）时，才能执行此操作
	 * 
	 * @param jobId
	 *            要下载的jobId
	 * @param file
	 *            保存的目标文件
	 * @return 保存的目标文件的句柄对象
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public File downloadJobOutput(String jobId, File file)
			throws OASClientException, OASServerException {
		return archiveManager.downloadJobOutput(oasProperty.getVaultName(),
				jobId, file);
	}

	/**
	 * 下载Job输出到文件，只有当Job的状态是Succeeded或Failed（到达终结状态）时，才能执行此操作
	 * 
	 * @param jobId
	 *            要下载的jobId
	 * @param file
	 *            保存的目标文件
	 * @return 异步任务传输对象，可获得传输信息
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public Transfer<File> downloadJobOutputAsync(String jobId, File file)
			throws OASClientException, OASServerException {
		Transfer<File> downloadJobOutputAsync = archiveManager
				.downloadJobOutputAsync(oasProperty.getVaultName(), jobId, file);
		downloadJobOutputAsync.addProgressListener(new ProgressListener() {
			@Override
			public void onStart(String id) {
				// 任务开始时调用，其中id为Multipart Upload任务ID，对于一般上传任务id为空
				logger.debug("Start! Upload ID: " + id);
			}

			@Override
			public void onProgressed(long current, long total) {
				// 上传进度，total为文件字节大小，current为当前已上传字节数
				logger.debug("Progress: " + current + " / " + total);
			}

			@Override
			public boolean onError(Range range, Throwable t) {
				// 出错时调用，range是出错的字节范围，t是相应的错误
				// 当返回true时，BaseTransfer会进行重试，false则放弃
				logger.debug("ERROR!!!");
				return false;
			}

			@Override
			public void onCompleted() {
				// 任务完成时调用
				logger.debug("Upload complete");
			}
		});
		downloadJobOutputAsync.start();
		final Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				logger.debug("Running time: "
						+ downloadJobOutputAsync.getRunningTime() + " seconds");
				logger.debug("Completed size: "
						+ downloadJobOutputAsync.getCompletedSize() + " bytes");
				logger.debug("Total size: "
						+ downloadJobOutputAsync.getTotalSize() + " bytes");
				logger.debug("Average speed: "
						+ downloadJobOutputAsync
								.getAverageSpeedInBytesPerSecond() + " B/s");
				if (downloadJobOutputAsync.isComplete()) {
					timer.cancel();
					synchronized (downloadJobOutputAsync) {
						downloadJobOutputAsync.notify();
					}
				}
			}

		}, 0, 1000);
		synchronized (downloadJobOutputAsync) {
			try {
				downloadJobOutputAsync.wait();
			} catch (InterruptedException e) {
				logger.error("", e);
			}
		}
		// 任务结束
		logger.debug("=============================");
		logger.debug("Running time: " + downloadJobOutputAsync.getRunningTime()
				+ " seconds");
		logger.debug("Completed size: "
				+ downloadJobOutputAsync.getCompletedSize() + " bytes");
		logger.debug("Total size: " + downloadJobOutputAsync.getTotalSize()
				+ " bytes");
		logger.debug("Average speed: "
				+ downloadJobOutputAsync.getAverageSpeedInBytesPerSecond()
				+ " B/s");
		return downloadJobOutputAsync;
	}

	/**
	 * 实例化JobMonitor
	 * 
	 * @param jobId
	 *            要实例化的jobId
	 * @return
	 * @throws OASClientException
	 * @throws OASServerException
	 */
	public JobMonitor getJobMonitor(String jobId){
		return archiveManager.getJobMonitor(oasProperty.getVaultName(), jobId);
	}
	
	/**
	 * @author xiongxiaotun <br/>
	 * @Title: checkJobFinishedWithRefresh <br/>
	 * @Description: 向OAS服务发送一个请求，获取Job的最新状态 <br/>
	 * @param jobMonitor
	 * @version V1.0 <br/>
	 */
	public boolean checkJobFinishedWithRefresh(String jobId) {
		if(StringUtils.isBlank(jobId)) {
			return true;
		}
		JobMonitor jobMonitor = getJobMonitor(jobId);
		if (null == jobMonitor) {
			return true; // 空任务，默认已经完成
		}
		return jobMonitor.checkJobFinishedWithRefresh();
	}

	// 低级接口======================================================================

	/**
	 * @author xiongxiaotun <br/>
	 * @Title: destory <br/>
	 * @Description: 销毁方法的注解方式 <br/>
	 * @version V1.0 <br/>
	 */
	@PreDestroy
	public void destory() {
		logger.debug("destory oas manager start...");
		if (null != archiveManager) {
			archiveManager.close();
		}
		if (null != aliyunOASClient) {
			aliyunOASClient.close();
		}
		logger.debug("destory  oas manager end.");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
//		logger.debug("create oas manager start...");
//		// 初始化认证
//		ServiceCredentials credentials = new ServiceCredentials(
//				oasProperty.getKeyId(), oasProperty.getKeySecret());
//		// 服务地址
//		ServiceHost serviceHost = new ServiceHost(
//				oasProperty.getClientEndPoint(), 80);
//		// 客户端配置
//		ClientConfiguration clientConfiguration = new ClientConfiguration();
//		// 使用AliyunOASClient初始化
//		aliyunOASClient = OASFactory.aliyunOASClientFactory(serviceHost,
//				credentials, clientConfiguration).withLogger();
//		archiveManager = OASFactory.archiveManagerFactory(aliyunOASClient)
//				.withNumConcurrence(5).withMaxRetryTimePerRequest(3);
//
//		CreateVaultRequest createRequest = new CreateVaultRequest()
//				.withVaultName(oasProperty.getVaultName());
//		CreateVaultResult result = aliyunOASClient.createVault(createRequest);
//		logger.debug("create oas manager end. vaultId is {}.",
//				result.getVaultId());
	}
}
